home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / grafik / raytracing / rayshade-4.0.6.3 / libray / libobj / cone.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-09  |  6.7 KB  |  327 lines

  1. /*
  2.  * cone.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * cone.c,v 4.1 1994/08/09 07:58:15 explorer Exp
  17.  *
  18.  * cone.c,v
  19.  * Revision 4.1  1994/08/09  07:58:15  explorer
  20.  * Bump version to 4.1
  21.  *
  22.  * Revision 1.1.1.1  1994/08/08  04:52:08  explorer
  23.  * Initial import.  This is a prerelease of 4.0.6enh3, or 4.1 possibly.
  24.  *
  25.  * Revision 4.0  91/07/17  14:36:46  kolb
  26.  * Initial version.
  27.  * 
  28.  */
  29. #include "geom.h"
  30. #include "cone.h"
  31.  
  32. static Methods *iConeMethods = NULL;
  33. static char coneName[] = "cone";
  34.  
  35. unsigned long ConeTests, ConeHits;
  36.  
  37. Cone *
  38. ConeCreate(br, bot, ar, apex)
  39. Vector *bot, *apex;
  40. Float br, ar;
  41. {
  42.     Cone *cone;
  43.     Float tantheta, lprime, tlen, len, dtmp;
  44.     Vector axis, base, tmp;
  45.  
  46.     /*
  47.      * The passed basepoint must be closer to the origin of the
  48.      * cone than the apex point, implying that the base radius
  49.      * must be smaller than the apex radius.  If the values passed
  50.      * reflect the opposite, we switch everything.
  51.      */
  52.     if(ar < br) {
  53.         tmp = *bot;
  54.         *bot = *apex;
  55.         *apex = tmp;
  56.         dtmp = br;
  57.         br = ar;
  58.         ar = dtmp;
  59.     } else if (equal(ar, br)) {
  60.         RLerror(RL_WARN, "Cone is a cylinder -- discarding.\n");
  61.         return (Cone *)NULL;
  62.     }
  63.     /*
  64.      * Find the axis and axis length.
  65.      */
  66.     VecSub(*apex, *bot, &axis);
  67.     len = VecNormalize(&axis);
  68.     if (len < EPSILON) {
  69.         RLerror(RL_WARN, "Degenerate cone.\n");
  70.         return (Cone *)NULL;
  71.     }
  72.  
  73.     cone = (Cone *)share_malloc(sizeof(Cone));
  74.  
  75.     /*
  76.      * To render a cone, we transform the desired cone into
  77.      * a canonical, Z-axis aligned, unit length, unit radius
  78.      * at the apex cone.
  79.      *
  80.      * Here, we construct the transformation matrix to map
  81.      * from cone<-->world space.
  82.      */
  83.  
  84.     /*
  85.      * "tantheta" is the change in radius per unit length along
  86.      * the cone axis.
  87.      */
  88.     tantheta = (ar - br) / len;
  89.     /*
  90.      * lprime defines the distance along the axis where the cone starts
  91.      */
  92.     lprime = br / tantheta;
  93.     /*
  94.      * Find the true base (origin) of the cone.
  95.      */
  96.     VecScale(-lprime, axis, &base);
  97.     VecAdd(base, *bot, &base);
  98.     /*
  99.      * tlen is the total length of the cone.
  100.      */
  101.     tlen = lprime + len;
  102.     /*
  103.      * start_dist is the distance from the origin of the canonical
  104.      * cone at which the cone begins
  105.      */
  106.     cone->start_dist = lprime / tlen;
  107.     CoordSysTransform(&base, &axis, ar, tlen, &cone->trans);
  108.     return cone;
  109. }
  110.  
  111. Methods *
  112. ConeMethods()
  113. {
  114.     if (iConeMethods == (Methods *)NULL) {
  115.         iConeMethods = MethodsCreate();
  116.         iConeMethods->name = ConeName;
  117.         iConeMethods->create = (GeomCreateFunc *)ConeCreate;
  118.         iConeMethods->methods = ConeMethods;
  119.         iConeMethods->intersect = ConeIntersect;
  120.         iConeMethods->normal = ConeNormal;
  121.         iConeMethods->uv = ConeUV;
  122.         iConeMethods->bounds = ConeBounds;
  123.         iConeMethods->stats = ConeStats;
  124.         iConeMethods->checkbounds = TRUE;
  125.         iConeMethods->closed = FALSE;
  126.     }
  127.     return iConeMethods;
  128. }
  129.  
  130. /*
  131.  * Ray-cone intersection test.  This routine is far from optimal, but
  132.  * it's straight-forward and it works...
  133.  */
  134. int
  135. ConeIntersect(cone, ray, mindist, maxdist)
  136. Cone *cone;
  137. Ray *ray;
  138. Float mindist, *maxdist;
  139. {
  140.     Float t1, t2, a, b, c, disc, zpos, distfact;
  141.     Ray newray;
  142.     Vector nray, npos;
  143.     Float nmin;
  144.  
  145.     ConeTests++;
  146.  
  147.     /*
  148.      * Transform ray from world to cone space.
  149.      */
  150.     newray = *ray;
  151.     distfact = RayTransform(&newray, &cone->trans.itrans);
  152.     nray = newray.dir;
  153.     npos = newray.pos;
  154.     nmin = mindist * distfact;
  155.  
  156.     a = nray.x * nray.x + nray.y * nray.y - nray.z*nray.z;
  157.     b = nray.x * npos.x + nray.y * npos.y - nray.z*npos.z;
  158.     c = npos.x*npos.x + npos.y*npos.y - npos.z*npos.z;
  159.  
  160.     if (fabs(a) < EPSILON) {
  161.         /*
  162.          * Only one intersection point...
  163.          */
  164.         t1 = -0.5*c / b;
  165.         zpos = npos.z + t1 * nray.z;
  166.         if (t1 < nmin || zpos < cone->start_dist || zpos > 1.)
  167.             return FALSE;
  168.         t1 /= distfact;
  169.         if (t1 < *maxdist) {
  170.             *maxdist = t1;
  171.             ConeHits++;
  172.             return TRUE;
  173.         }
  174.         return FALSE;
  175.     } else {
  176.         disc = b*b - a*c;
  177.         if (disc < 0.)
  178.             return FALSE;        /* No possible intersection */
  179.         disc = sqrt(disc);
  180.         t1 = (-b + disc) / a;
  181.         t2 = (-b - disc) / a;
  182.         /*
  183.          * Clip intersection points.
  184.          */
  185.         zpos = npos.z + t1 * nray.z;
  186.         if (t1 < nmin || zpos < cone->start_dist || zpos > 1.) {
  187.             zpos = npos.z + t2 * nray.z;
  188.             if (t2 < nmin || zpos < cone->start_dist ||
  189.                 zpos > 1.)
  190.                 return FALSE;
  191.             else
  192.                 t1 = t2 / distfact;
  193.         } else {
  194.             zpos = npos.z + t2 * nray.z;
  195.             if (t2 < nmin || zpos < cone->start_dist ||
  196.                 zpos > 1.)
  197.                 t1 /= distfact;
  198.             else
  199.                 t1 = min(t1, t2) / distfact;
  200.         }
  201.         if (t1 < *maxdist) {
  202.             *maxdist = t1;
  203.             ConeHits++;
  204.             return TRUE;
  205.         }
  206.         return FALSE;
  207.     }
  208. }
  209.  
  210. /*
  211.  * Compute the normal to a cone at a given location on its surface.
  212.  */
  213. int
  214. ConeNormal(cone, pos, nrm, gnrm)
  215. Cone *cone;
  216. Vector *pos, *nrm, *gnrm;
  217. {
  218.     Vector npos;
  219.  
  220.     /*
  221.      * Transform intersection point to cone space.
  222.      */
  223.     npos = *pos;
  224.     PointTransform(&npos, &cone->trans.itrans);
  225.     
  226.     /*
  227.      * The following is equal to
  228.      * (pos X (0, 0, 1)) X pos
  229.      */
  230.     nrm->x = npos.x * npos.z;
  231.     nrm->y = npos.y * npos.z;
  232.     nrm->z = -npos.x * npos.x - npos.y * npos.y;
  233.  
  234.     /*
  235.      * Transform normal back to world space.
  236.      */
  237.     NormalTransform(nrm, &cone->trans.itrans);
  238.     *gnrm = *nrm;
  239.     return FALSE;
  240. }
  241.  
  242. void
  243. ConeUV(cone, pos, norm, uv, dpdu, dpdv)
  244. Cone *cone;
  245. Vector *pos, *norm, *dpdu, *dpdv;
  246. Vec2d *uv;
  247. {
  248.     Vector npos;
  249.     Float val;
  250.  
  251.     npos = *pos;
  252.     PointTransform(&npos, &cone->trans.itrans);
  253.  
  254.     uv->v = (npos.z - cone->start_dist) / (1. - cone->start_dist);
  255.     if (npos.z < EPSILON)
  256.         uv->u = 0.;
  257.     else {
  258.         val = npos.x / npos.z;
  259.         /*
  260.          * Be careful not to feed |val| > 1 to acos
  261.          */
  262.         if (val > 1.)
  263.             uv->u = 0.;
  264.         else if (val < -1.)
  265.             uv->u = 0.5;
  266.         else {
  267.             uv->u = acos(val) / TWOPI;
  268.             if (npos.y < 0.)
  269.                 uv->u = 1. - uv->u;
  270.         }
  271.     }
  272.     /*
  273.      * dpdv = pos
  274.      * dpdu = dpdv X norm = (-norm->y, norm->x, 0.)
  275.      */
  276.     if (dpdu) {
  277.         *dpdv = npos;
  278.         dpdu->x = -npos.y;
  279.         dpdu->y = npos.x;
  280.         dpdu->z = 0.;
  281.         VecTransform(dpdu, &cone->trans.trans);
  282.         VecTransform(dpdu, &cone->trans.trans);
  283.         (void)VecNormalize(dpdu);
  284.         (void)VecNormalize(dpdv);
  285.     }
  286. }
  287.  
  288. /*
  289.  * Return the extent of a cone.
  290.  */
  291. void
  292. ConeBounds(cone, bounds)
  293. Cone *cone;
  294. Float bounds[2][3];
  295. {
  296.     bounds[LOW][X] = bounds[LOW][Y] = -1;
  297.     bounds[HIGH][X] = bounds[HIGH][Y] = 1;
  298.     bounds[LOW][Z] = cone->start_dist;
  299.     bounds[HIGH][Z] = 1;
  300.     /*
  301.      * Transform bounding box to world space.
  302.      */
  303.     BoundsTransform(&cone->trans.trans, bounds);
  304. }
  305.  
  306. char *
  307. ConeName()
  308. {
  309.     return coneName;
  310. }
  311.  
  312. void
  313. ConeStats(tests, hits)
  314. unsigned long *tests, *hits;
  315. {
  316.     *tests = ConeTests;
  317.     *hits = ConeHits;
  318. }
  319.  
  320. void
  321. ConeMethodRegister(meth)
  322. UserMethodType meth;
  323. {
  324.     if (iConeMethods)
  325.         iConeMethods->user = meth;
  326. }
  327.